import { Graph, Node, Edge, StringExt } from "@antv/x6";
import { NodeType, Position, NODE_TYPE_LIST } from "./types";
import { getNodeTypes } from "hqhui";

/**
 * @file utils.ts
 * @description 提供流程图操作的工具函数
 */

/**
 * 根据起点获取下游节点的位置信息
 * @param node 起始节点
 * @param graph 图表实例
 * @param dx 水平偏移量，默认250
 * @param dy 垂直偏移量，默认100
 * @returns 位置信息对象，包含x和y坐标
 */
export const getDownstreamNodePosition = (
  node: Node,
  graph: Graph,
  dx = 250,
  dy = 100
): Position => {
  // 找出画布中以该起始节点为起点的相关边的终点id集合
  const downstreamNodeIdList: string[] = [];
  graph.getEdges().forEach((edge) => {
    const originEdge = edge.toJSON()?.data;
    if (originEdge?.source === node.id) {
      downstreamNodeIdList.push(originEdge.target);
    }
  });

  // 获取起点的位置信息
  const position = node.getPosition();
  let minX = Infinity;
  let maxY = -Infinity;

  graph.getNodes().forEach((graphNode) => {
    if (downstreamNodeIdList.includes(graphNode.id)) {
      const nodePosition = graphNode.getPosition();
      if (nodePosition.x < minX) {
        minX = nodePosition.x;
      }
      if (nodePosition.y > maxY) {
        maxY = nodePosition.y;
      }
    }
  });

  // 如果有下游节点，在最下方节点下一行放置新节点；否则在当前节点右侧放置
  return {
    x: minX !== Infinity ? minX : position.x + dx,
    y: maxY !== -Infinity ? maxY + dy : position.y,
  };
};

/**
 * 根据节点的类型获取连接桩配置
 * @param type 节点类型
 * @param nodeId 节点ID
 * @returns 连接桩配置数组
 */
export const getPortsByType = (type: NodeType | string, nodeId: string) => {
  switch (type) {
    case NodeType.INPUT:
      // 输入节点只有输出连接桩
      return [
        {
          id: `${nodeId}-out`,
          group: "out",
        },
      ];
    case NodeType.OUTPUT:
      // 输出节点只有输入连接桩
      return [
        {
          id: `${nodeId}-in`,
          group: "in",
        },
      ];
    default:
      // 中间处理节点既有输入也有输出连接桩
      return [
        {
          id: `${nodeId}-in`,
          group: "in",
        },
        {
          id: `${nodeId}-out`,
          group: "out",
        },
      ];
  }
};

/**
 * 创建节点并添加到画布
 * @param type 节点类型
 * @param graph 图表实例
 * @param position 节点位置（可选）
 * @returns 新创建的节点对象
 */
export const createNode = (
  type: NodeType | string,
  graph: Graph,
  position?: Position
): Node => {
  // 统计同类型节点数量，用于生成唯一标签
  const sameTypeNodes = graph
    .getNodes()
    .filter((item) => item.getData()?.value === type);

  // 组合本地节点类型列表和动态节点类型列表
  const nodeTypes = getNodeTypes();
  const allNodeTypes = [...NODE_TYPE_LIST, ...nodeTypes];
  
  // 获取节点类型显示名称
  const typeName = allNodeTypes.find(
    (item) => item.value === type
  )?.label;

  // 生成唯一ID并创建节点
  const id = StringExt.uuid();
  const node = graph.addNode({
    id,
    shape: "custom-node",
    x: position?.x,
    y: position?.y,
    ports: getPortsByType(type, id),
    data: {
      label: `${typeName}_${sameTypeNodes.length + 1}`,
      value: type,
    },
  });

  return node as Node;
};

/**
 * 创建边并添加到画布
 * @param source 源节点ID
 * @param target 目标节点ID
 * @param graph 图表实例
 * @returns 新创建的边对象
 */
export const createEdge = (source: string, target: string, graph: Graph) => {
  const edge = graph.addEdge({
    id: StringExt.uuid(),
    shape: "data-processing-curve",
    source: {
      cell: source,
      port: `${source}-out`,
    },
    target: {
      cell: target,
      port: `${target}-in`,
    },
    zIndex: -1,
    data: {
      source,
      target,
    },
  });

  return edge as Edge;
};